# This script need mcall.c, user must add mcall.c into project.
# Here is a structure, which is define in mcall.c.
# typedef struct {
#    uint32_t len;
#    uint32_t para[MCALL_FUNC_PARA_MAX_NUM];
# } MCallRun_t;

###############################################################################
# Called function name max 100 chars.
set $mcall_name = (char[100])"None"
# 0:INT mode  1:normal
set $mcall_mode = 0
set $mcall_stop1 = 1
set $mcall_stop2 = 1
set $mcall_mcall = 0

################################################################################
define mcall
	dont-repeat
	if $argc == 0
		mcall_ret
	else
		if $argc == 1
			# Show function type.
			call $arg0
		else
			set $mcall_name = "$arg0"
			#set $mcall_para = mCallRun.para
			#set mCallRun.len = $argc
			set $mcall_para = ((unsigned int*)&mCallRun)+1
			set *((unsigned int*)&mCallRun) = $argc
			set $mcall_para[0] = $arg0
			if $argc > 1
				set $mcall_para[1] = $arg1
			end
			if $argc > 2
				set $mcall_para[2] = $arg2
			end
			if $argc > 3
				set $mcall_para[3] = $arg3
			end
			if $argc > 4
				set $mcall_para[4] = $arg4
			end
			if $argc > 5
				set $mcall_para[5] = $arg5
			end
			if $argc > 6
				set $mcall_para[6] = $arg6
			end
			if $argc > 7
				set $mcall_para[7] = $arg7
			end
			if $argc > 8
				set $mcall_para[8] = $arg8
			end
			if $argc > 9
				set $mcall_para[9] = $arg9
			end
			if $mcall_mode == 0
				set $mcall_pc = $pc
				set $epsr = $psr
				set $epc = $mcall_pc
				set $psr |= 0x80000000
				if $mcall_mcall
					set $pc = $mcall_mcall
				else
					set $pc = mCallFuncInt
				end
			else
				set $mcall_pc = $pc
				set $mcall_psr = $psr
				set $mcall_r15 = $r15
				set $r15 = $mcall_pc
				if $mcall_mcall
					set $pc = $mcall_mcall
				else
					set $pc = mCallFuncNormal
				end
			end
			if $mcall_stop1
				thbreak $arg0
			end
			if $mcall_mode
				thbreak *$mcall_pc
				commands
					silent
					set $r15 = $mcall_r15
					set $psr = $mcall_psr
					if $mcall_stop2 == 0
						c
					else
						mcall_ret
					end
				end
			else
				if $mcall_stop2
					thbreak *$mcall_pc
					commands
						silent
						mcall_ret
					end
				end
			end
			c
		end
	end
end

document mcall
Usage: mcall [func] [para1] [para2] [...]

like: mcall
      mcall printf
      mcall printf "%d,%d\n" 1 2

If only "mcall", gdb will print the last called function return value.
If only one [func], gdb will print function info.
If more then one [para], gdb will call mCallFunc() to call the function \
which define in mcall.c.
If the called function has none parameter, set [para1] is 0 or any value.
String parameter need malloc() support.
This cmd cannot check parameter right or not, it's ensure by user.
This cmd support 9 parameters max, because gdb user define only support 10 args.
When cmd run, it will make a hard breakpoint at the called function entry, \
this breakpoint only active once.
This cmd will not redo when user input a space enter.
Redefine "mcall_ret" can change "mcall" print return value mode, see \
"help mcall_ret".
end

###############################################################################
define mcall_config
	dont-repeat
	if $argc
		set $mcall_stop1 = $arg0
		set $mcall_stop2 = $arg1
		if $argc > 2
			set $mcall_mode = $arg2
			if $argc == 4
				set $mcall_mcall = $arg3
			end
		end
	else
		if $mcall_stop1
			echo [stop1]: STOP\n
		else
			echo [stop1]: RUN\n
		end
		if $mcall_stop2
			echo [stop2]: STOP\n
		else
			echo [stop2]: RUN\n
		end
		if $mcall_mode
			echo [mode]:  NORMAL\n
		else
			echo [mode]:  INT\n
		end
		echo [mcall]:
		if $mcall_mcall
			printf " 0x%08X\n", $mcall_mcall
		else
			if $mcall_mode
				printf " 0x%08X\n", (unsigned int)mCallFuncNormal
			else
				printf " 0x%08X\n", (unsigned int)mCallFuncInt
			end
		end
	end
end

document mcall_config
Usage: mcall_config
       mcall_config [mcall]
       mcall_config [stop1] [stop2]
       mcall_config [stop1] [stop2] [mode]
       mcall_config [stop1] [stop2] [mode] [mcall]

like: mcall_config
      mcall_config 0x20001000
      mcall_config 0 0
      mcall_config 0 1 1
      mcall_config 0 0 0 0x20001000
If no args, it print current configure.
If one arg, it set mCallFunc = $arg0.
If two args, it set stop1 and stop2.
If three args, it set stop1 stop2 and mode.
If fore args, it set stop1 stop2 mode and set mCallFunc = $arg3.
The args means:
  [mcall] Address of mCallFunc.
  [stop1] 0: No stop when pc run to func.
          1: Stop when pc run to func.
  [stop2] 0: No stop when pc run back from function.
             1: Stop when pc run back from function.
  [mode]  0: INT, call a func like a interrupt happend, it can need not hardbreak.
          1: NORMAL, need at least a hardbreak before function finish.
  default: [stop1]1,[stop2]0,[mode]0,[mcall]0
end

###############################################################################
define mcall_value
	# printf cmd need malloc() support.
	set $mcall_i = 0
	while $mcall_name[$mcall_i]
		printf "%c", $mcall_name[$mcall_i]
		set $mcall_i++
	end
	echo () return:\n
	if $argc == 0
		p /x *(((unsigned int*)&mCallRun)+1)
	else
		p ($arg0)*(((unsigned int*)&mCallRun)+1)
	end
end

document mcall_value
Usage: mcall_value
       mcall_value [type]

like: mcall_value
      mcall_value int
If no args, print function return value with "p/x" cmd.
User can input the type of the return value, gdb will turn the type and then print.
This can used in "mcall_ret" cmd, see "help mcall_ret".
end

###############################################################################
define mcall_ret
	mcall_value
end

document mcall_ret
Usage: This cmd should be redefine, or use the default.

like: (gdb) define mcall_ret
      > mcall_value int
      > end
This cmd is called by "mcall" cmd to print return value, redefine this cmd can \
tell "mcall" the type of the called function. It should use "mcall_value" to \
set type. see "help mcall_value".
end



